package classifiers;

import draw.ExploringMedics;
import histogram.HistogramDescr;
import java.util.LinkedList;

public class CircleClassifier {

    int neiroImage[][];
    int binImage[][];
    int markedImage[][];
    int height;
    int width;

    public CircleClassifier(int[][] neiroImage, int[][] binImage) {
        this.neiroImage = neiroImage;
        this.binImage = binImage;

        height = neiroImage[0].length;
        width = neiroImage.length;
        markedImage = new int[width][height];

        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                markedImage[i][j] = 0;
            }
        }

    }
    public int regionSize = 0;
    public int perimetr = 0;
    public int minx = Integer.MAX_VALUE;
    public int miny = Integer.MAX_VALUE;
    public int maxx = 0;
    public int maxy = 0;
    private static final int IN_COMPONENT = 875;
    public static final int CIRCLES = 90;
    public static final int OVAL = 91;
    public static final int NO_MARK = 0;
    private final int START_MARK = 100;

    public void findConnectedComponent(int xPoint, int yPoint, int mark) {

        LinkedList<Integer> xQueue = new LinkedList<Integer>();
        LinkedList<Integer> yQueue = new LinkedList<Integer>();

        xQueue.push(xPoint);
        yQueue.push(yPoint);

        int dx[] = {-1, 1, 0, 0};
        int dy[] = {0, 0, -1, 1};

        regionSize = 1;
        perimetr = 0;
        minx = Integer.MAX_VALUE;
        miny = Integer.MAX_VALUE;
        maxx = 0;
        maxy = 0;

        while (!xQueue.isEmpty()) {
            int x = xQueue.pop();
            int y = yQueue.pop();

            if (x >= width - 1 || y >= height - 1 || x <= 0 || y <= 0) {
                continue;
            }

            if (binImage[x][y] == ExploringMedics.WHITE
                    && neiroImage[x][y] == HistogramDescr.MITAH
                    && markedImage[x][y] == 0) {

                markedImage[x][y] = mark;

                regionSize++;

                boolean isEdge = false;
                for (int i = x - 1; i <= x + 1; i++) {
                    for (int j = y - 1; j <= y + 1; j++) {
                        if (binImage[i][j] == ExploringMedics.BLACK
                                && neiroImage[i][j] == HistogramDescr.MITAH) {
                            isEdge = true;
                        }
                    }
                }
                if (isEdge) {
                    perimetr++;
                }

                minx = x < minx ? x : minx;
                miny = y < miny ? y : miny;
                maxx = x > maxx ? x : maxx;
                maxy = y > maxy ? y : maxy;

                for (int i = 0; i < 4; i++) {
                    xQueue.push(x + dx[i]);
                    yQueue.push(y + dy[i]);
                }
            }
        }

//        System.out.println(regionSize);
    }
    private int minWidthCriter = 0;
    private int maxWidthCriter = 0;
    private int minHeightCriter = 0;
    private int maxHeightCriter = 0;
    private int minSquareCriter = 0;
    private int maxSquareCriter = 0;
    private int minPerimDivSqCriter = 0;
    private int maxPerimDivSqCriter = 0;

    public void setExploy(int wMin, int wMax, int hMin, int hMax, int sMin, int sMax, int minDiv, int maxDiv) {
        minWidthCriter = wMin;
        maxWidthCriter = wMax;
        minHeightCriter = hMin;
        maxHeightCriter = hMax;
        minSquareCriter = sMin;
        maxSquareCriter = sMax;
        minPerimDivSqCriter = minDiv;
        maxPerimDivSqCriter = maxDiv;
    }

    public void exployAll() {
        int regionCount = 0;
        int needRegion = 0;
        int mark = START_MARK;
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                if (binImage[i][j] == ExploringMedics.WHITE && neiroImage[i][j] == HistogramDescr.MITAH) {
                    findConnectedComponent(i, j, mark);

                    int perimSq = perimetr * perimetr / regionSize;

                    if (maxx - minx > minWidthCriter
                            && maxy - miny > minHeightCriter
                            && maxx - minx < maxWidthCriter
                            && maxy - miny < maxHeightCriter
                            && regionSize > minSquareCriter
                            && regionSize < maxSquareCriter
                            && perimSq < maxPerimDivSqCriter) {

                        needRegion++;

                        int more = Math.max(maxy - miny, maxx - minx);
                        int low = Math.min(maxy - miny, maxx - minx);

                        if (1.0 * low / more > 0.8) {
                            markComponent(mark, CIRCLES);
                        } else {
                            markComponent(mark, OVAL);
                        }

                    }
                    mark++;
//                    System.out.println(minx + "  " + maxx + " " + miny + "  " + maxy + " " + regionSize + " " + perimSq);
                    regionCount++;
                }
            }
        }
        System.out.println("regions " + regionCount);
        System.out.println("needRegions " + needRegion);
    }

    public void markComponent(int oldMark, int newMark) {

        for (int i = minx; i <= maxx; i++) {
            for (int j = miny; j <= maxy; j++) {
                if (markedImage[i][j] == oldMark) {
                    markedImage[i][j] = newMark;
                }
            }
        }

    }

    public int[][] getMarkedImage() {
        return markedImage;
    }
}
